package com.pan.behavioral.Interpreter;

import com.pan.behavioral.Interpreter.exprerssoin.Expression;
import com.pan.behavioral.Interpreter.exprerssoin.NonTerminalExpression;
import com.pan.behavioral.Interpreter.exprerssoin.TerminalExpression;
import com.pan.behavioral.Interpreter.exprerssoin.impl.*;

import java.util.HashMap;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MyInterpreter {

    Stack<Expression> expressionStack = new Stack<>();

    HashMap<String, String> contentMap = new HashMap<>();

    private void addTerminalExpression(TerminalExpression expression) {
        if (expressionStack.empty()) {
            expressionStack.push(expression);
        } else {
            Expression root = expressionStack.pop();
            ((NonTerminalExpression) root).setRightExpression(expression);
            expressionStack.push(root);
        }
    }

    private void addNonTerminalExpression(NonTerminalExpression nonTerminalExpression) {
        if (!expressionStack.empty()) {
            Expression left = expressionStack.pop();
            nonTerminalExpression.setLeftExpression(left);
            expressionStack.push(nonTerminalExpression);
        }
    }

    public void handles(String context) {
        for (String s : context.split(";")) {
            handle(s);
        }
    }

    public Object handle(String context) {
        for (; context.length() != 0; ) {
            context = toExpression(context);
        }
        if (expressionStack.empty()) {
            return null;
        }
        return expressionStack.pop().interpreter();
    }

    Pattern numPattern = Pattern.compile("^\\d+");
    Pattern operatePattern = Pattern.compile("^[+-]");
    Pattern strPattern = Pattern.compile("^([a-z]+)|('.*')");
    Pattern valuePattern = Pattern.compile("^\\w+\\s*=\\s*(\\d+|'.*'$|\\w+)");

    private String toExpression(String context) {
        context = context.strip();
        Matcher valueMatcher = valuePattern.matcher(context);
        if (valueMatcher.find()) {
            String kv = valueMatcher.group();
            String key = kv.substring(0, kv.indexOf("=")).strip();
            String value = kv.substring(kv.indexOf("=") + 1);
            contentMap.put(key, value);
            return "";
        }

        Matcher numMatcher = numPattern.matcher(context);
        Matcher operateMatcher = operatePattern.matcher(context);
        Matcher strMather = strPattern.matcher(context);

        if (numMatcher.find()) {
            String token = numMatcher.group();
            NumberExpression numberExpression = new NumberExpression(token);
            addTerminalExpression(numberExpression);
            return context.substring(token.length());
        } else if (operateMatcher.find()) {
            String operate = operateMatcher.group();
            NonTerminalExpression expression;
            if (isPlus(operate)) {
                expression = new PlusExpression();
            } else if (isReduce(operate)) {
                expression = new ReduceExpression();
            }else {
                throw new RuntimeException("无法匹配该操作符：" + operate);
            }
            addNonTerminalExpression(expression);
            return context.substring(operate.length());
        } else if (strMather.find()) {
            String str = strMather.group();
            if (isPrint(str)) {
                NonTerminalExpression expression = new PrintExpression();
                addNonTerminalExpression(expression);
                return context.substring(str.length());
            } else if (contentMap.containsKey(str)) {
                String value = contentMap.get(str);
                return context.replaceAll("^" + str, value);
            } else if (isString(str)) {
                TerminalExpression terminalExpression =
                        new StringExpression(str.substring(1, str.length() - 1));
                addTerminalExpression(terminalExpression);
                return context.substring(str.length());
            }else {
                throw new RuntimeException("无法识别字符："+str);
            }
        } else {
            throw new RuntimeException("错误语法：" + context);
        }

    }

    private boolean isReduce(String str) {
        if (str.equals("-")) {
            return true;
        }
        return false;
    }

    private boolean isPlus(String str) {
        if (str.equals("+")) {
            return true;
        }
        return false;
    }

    private boolean isString(String str) {
        if (str.startsWith("'") && str.endsWith("'")) {
            return true;
        }
        return false;
    }

    private boolean isPrint(String str) {
        if (str.equals("print")) {
            return true;
        }
        return false;
    }
}
